package web

import (
	"fmt"
	"net/http"
	"time"

	regexp "github.com/dlclark/regexp2"

	"webook/internal/domain"
	"webook/internal/service"

	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	jwt "github.com/golang-jwt/jwt/v5"
)

var ErrUserDuplicateEmail = service.ErrUserDuplicateEmail

// 保证UserHandler实现了handler接口
var _ handler = (*UserHandler)(nil)

// 设计用户的登录注册以及用户信息的编辑查看功能相关的路由
type UserHandler struct {
	svc         *service.UserService
	emailExp    *regexp.Regexp
	passwordExp *regexp.Regexp
	CodeService *service.CodeService
}

func NewUserHandler(svc *service.UserService, codeSvc *service.CodeService) *UserHandler {
	const (
		emailRegexPattern    = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
		passWordRegexPattern = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+])[A-Za-z\\d!@#$%^&*()_+]{8,}$"
	)
	emilaExp := regexp.MustCompile(emailRegexPattern, regexp.None)
	passWordExp := regexp.MustCompile(passWordRegexPattern, regexp.None)
	return &UserHandler{
		svc:         svc,
		emailExp:    emilaExp,
		passwordExp: passWordExp,
		CodeService: codeSvc,
	}
}

func (u *UserHandler) RegisterRoutes(r *gin.Engine) {
	ug := r.Group("/users")
	ug.POST("/signup", u.Signup)
	ug.POST("/login", u.LoginJwt)
	ug.POST("/edit", u.Edit)
	ug.GET("/profile", u.Profile)
	ug.POST("/login_sms/code/send", u.LoginSMSCode)
	ug.POST("/login_sms", u.LoginSMS)
}

func (u *UserHandler) LoginSMS(c *gin.Context) {
	type Req struct {
		Phone string `json:"phone"`
		Code  string `json:"code"`
	}
	var req Req
	const biz = "login"
	if err := c.Bind(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": err.Error(),
		})
		return
	}
	err := u.CodeService.Verify(c.Request.Context(), biz, req.Phone, req.Code)
	if err != nil {
		if err == service.ErrCodeVerifyTooMany {
			c.JSON(http.StatusOK, gin.H{
				"code": 429,
				"msg":  "验证码错误次数过多",
			})
			return
		} else if err == service.ErrCodeVerifyInvalid {
			c.JSON(http.StatusOK, gin.H{
				"code": 400,
				"msg":  "验证码错误",
			})
			return
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{
				"code": 500,
				"msg":  "系统错误",
			})
			return
		}
	}
	// 这里应该处理登录的业务，也就是应该把JWT的token返回给前端，前端在登录的时候把token存储到本地，然后每次请求的时候把token发送给后端，后端通过token来判断用户是否登录
	//但是还存在一个问题，就是这里用手机号登录的时候，不能判断用户是否已经注册，所以需要先判断用户是否注册，如果用户没有注册，则需要先注册，然后登录

	user, err := u.svc.FindOrCreate(c.Request.Context(), req.Phone)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "系统错误",
		})
		return
	}
	err = u.setJWTToken(c, user)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "系统错误",
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "验证码校验通过",
	})
}

func (u *UserHandler) setJWTToken(c *gin.Context, user domain.User) error {
	claims := UserClaims{
		UserId: user.Id,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 30)),
		},
		UserAgent: c.Request.UserAgent(),
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokentstr, err := token.SignedString([]byte("1234567890"))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "系统错误",
		})
		return err
	}
	c.Header("x-jwt-token", tokentstr)
	return nil
}

func (u *UserHandler) Signup(c *gin.Context) {
	type SignupReq struct {
		Email           string `json:"email"`
		ConfirmPassword string `json:"confirmPassword"`
		Password        string `json:"password"`
	}
	var req SignupReq
	//Bind函数会把请求的json数据绑定到req变量上
	if err := c.Bind(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": err.Error(),
		})
		return
	}

	ok, err := u.emailExp.MatchString(req.Email)
	if err != nil {
		c.String(http.StatusOK, "系统错误")
		return
	}
	if !ok {
		c.String(http.StatusOK, "邮箱格式不正确")
		return
	}
	if req.Password != req.ConfirmPassword {
		c.String(http.StatusOK, "两次密码不一致")
		return
	}

	ok, err = u.passwordExp.MatchString(req.Password)
	if err != nil {
		c.String(http.StatusOK, "系统错误")
		return
	}
	if !ok {
		c.String(http.StatusOK, "密码格式不正确")
		return
	}
	err = u.svc.Signup(c.Request.Context(), domain.User{
		Email:    req.Email,
		Password: req.Password,
	})
	if err == service.ErrUserDuplicateEmail {
		c.String(http.StatusOK, "邮箱已存在")
		return
	}
	if err != nil {
		c.String(http.StatusOK, "系统错误")
		return
	}
	//接下来就是数据库的操作
	fmt.Printf("%v", req)
	c.JSON(http.StatusOK, gin.H{
		"message": "注册成功",
	})
}

func (u *UserHandler) Login(c *gin.Context) {
	type LoginReq struct {
		Email    string `json:"email"`
		Password string `json:"password"`
	}
	var req LoginReq
	if err := c.Bind(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": err.Error(),
		})
		return
	}
	user, err := u.svc.Login(c, req.Email, req.Password)
	if err == service.ErrInvalidUserOrPassword {
		c.String(http.StatusOK, "用户名或密码错误")
		return
	}
	if err != nil {
		c.String(http.StatusOK, "系统错误")
		return
	}
	//设置session，把用户id存入session中
	sess := sessions.Default(c)
	sess.Set("userId", user.Id)
	sess.Options(sessions.Options{
		MaxAge: 15,
	})
	sess.Save()

	c.JSON(http.StatusOK, gin.H{
		"message": "登录成功",
	})
}

func (u *UserHandler) Edit(c *gin.Context) {
	// 断点1：请求开始
	type EditReq struct {
		Nickname string `json:"nickname"`
		Birthday string `json:"birthday"`
		AboutMe  string `json:"aboutMe"`
	}
	var req EditReq
	if err := c.Bind(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": err.Error(),
		})
		return
	}

	// 断点2：数据验证后
	// 数据验证
	if req.Nickname != "" && len(req.Nickname) > 50 {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "昵称长度不能超过50个字符",
		})
		return
	}

	if req.AboutMe != "" && len(req.AboutMe) > 500 {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "自我介绍长度不能超过500个字符",
		})
		return
	}

	// 验证生日格式 (YYYY-MM-DD)
	if req.Birthday != "" {
		_, err := time.Parse("2006-01-02", req.Birthday)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{
				"error": "生日格式不正确，请使用YYYY-MM-DD格式",
			})
			return
		}
	}

	// 断点3：session验证后
	sess := sessions.Default(c)
	userId := sess.Get("userId")
	if userId == nil {
		c.JSON(http.StatusUnauthorized, gin.H{
			"error": "用户未登录",
		})
		return
	}

	// 断点4：数据库更新前
	err := u.svc.UpdateUserProfile(c.Request.Context(), domain.User{
		Id:       userId.(int64),
		Nickname: req.Nickname,
		Birthday: req.Birthday,
		AboutMe:  req.AboutMe,
	})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "系统错误",
		})
		return
	}

	// 断点5：返回响应前
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "更新用户信息成功",
	})
}

func (u *UserHandler) Profile(c *gin.Context) {
	// 从JWT中间件传递的上下文中获取用户ID
	userId, exists := c.Get("userId")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{
			"error": "用户未登录",
		})
		return
	}

	user, err := u.svc.GetUserById(c.Request.Context(), userId.(int64))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "系统错误",
		})
		return
	}

	// 返回用户信息，但不包含敏感信息如密码
	c.JSON(http.StatusOK, gin.H{
		"Id":       user.Id,
		"Email":    user.Email,
		"Nickname": user.Nickname,
		"Birthday": user.Birthday,
		"AboutMe":  user.AboutMe,
		"Ctime":    user.Ctime,
		"Phone":    user.Phone,
	})
}
func (u *UserHandler) Logout(c *gin.Context) {
	sess := sessions.Default(c)
	sess.Options(sessions.Options{
		MaxAge: -1,
	})
	sess.Save()
	sess.Delete("userId")
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "退出登录成功",
	})
}
func (u *UserHandler) LoginJwt(c *gin.Context) {
	type LoginReq struct {
		Email    string `json:"email"`
		Password string `json:"password"`
	}
	var req LoginReq
	if err := c.Bind(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": err.Error(),
		})
		return
	}
	user, err := u.svc.Login(c, req.Email, req.Password)
	if err == service.ErrInvalidUserOrPassword {
		c.String(http.StatusOK, "用户名或密码错误")
		return
	}
	if err != nil {
		c.String(http.StatusOK, "系统错误")
		return
	}
	// 创建JWT claims
	claims := UserClaims{
		UserId: user.Id,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 30)),
		},
		UserAgent: c.Request.UserAgent(),
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokentstr, err := token.SignedString([]byte("1234567890"))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "系统错误",
		})
		return
	}
	c.Header("x-jwt-token", tokentstr)
	fmt.Println(user)
	c.JSON(http.StatusOK, gin.H{
		"message": "登录成功",
	})
}

type UserClaims struct {
	UserId int64 `json:"userId"`
	jwt.RegisteredClaims
	UserAgent string `json:"user_agent"`
}

func (u *UserHandler) LoginSMSCode(c *gin.Context) {
	type Req struct {
		Phone string `json:"phone"`
	}
	const biz = "login"
	var req Req
	if err := c.Bind(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": err.Error(),
		})
		return
	}

	err := u.CodeService.Send(c.Request.Context(), biz, req.Phone)
	if err != nil {
		if err == service.ErrCodeSendTooMany {
			c.JSON(http.StatusOK, gin.H{
				"code": 429,
				"msg":  "发送验证码太频繁",
			})
			return
		} else if err == service.ErrCodeSendSystemError {
			c.JSON(http.StatusInternalServerError, gin.H{
				"code": 500,
				"msg":  "系统错误",
			})
			return
		}
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "发送验证码成功",
	})
}
